package com.ciei.dpagm.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ciei.dpagm.common.enums.ChipTypeEnum;
import com.ciei.dpagm.common.enums.ErrorCodeEnum;
import com.ciei.dpagm.common.enums.FormBusinessModuleEnum;
import com.ciei.dpagm.common.enums.ParameterConfigurationDataTypeEnum;
import com.ciei.dpagm.common.service.BaseService;
import com.ciei.dpagm.entity.*;
import com.ciei.dpagm.mapper.FormLayoutMapper;
import com.ciei.dpagm.util.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangyan
 * @date 2021/06/01
 */
@Service
public class FormLayoutService extends BaseService<FormLayoutMapper, FormLayout> {

    @Autowired
    private FormPropertyDefinitionService formPropertyDefinitionService;

    @Autowired
    private  FormComponentService formComponentService;

    @Autowired
    private  FormPropertyService formPropertyService;

    @Lazy
    @Autowired
    private DriverLibraryService driverLibraryService;

    @Lazy
    @Autowired
    private ChipService chipService;

    /**
     * 获取表单布局分页列表
     * @return
     */
    public JSONObject getFormLayoutPageList(PageParam pageParam){
        JSONObject resultData = new JSONObject();
        Map<String, Object> params=pageParam.getParams();
        int currentPage =pageParam.getCurrentPage();
        int pageSize =pageParam.getPageSize();
        QueryWrapper<FormLayout> queryWrapper = new QueryWrapper<>();
        String layoutName = (String) params.get("layoutName");
        if (!StringUtil.isNullOrEmpty(layoutName)){
            queryWrapper.lambda().like(FormLayout::getLayoutName, layoutName);
        }
        JSONArray queryParams = (JSONArray) params.get("queryParams");
        if (!queryParams.isEmpty()){
            queryWrapper.and(wrapper->{
                for (int  i = 0; i < queryParams.size(); i++) {
                    JSONObject queryParam = queryParams.getJSONObject(i);
                    Integer businessModule = queryParam.getInteger("businessModule");
                    List<Integer> classificationIds = queryParam.getJSONArray("classificationId").toJavaList(Integer.class);
                    if (businessModule != null && !classificationIds.isEmpty()){
                        wrapper.or(wrapper1->{
                            wrapper1.lambda().eq(FormLayout::getBusinessModule,businessModule);
                            wrapper1.lambda().in(FormLayout::getClassificationId,classificationIds);
                        });
                    }
                }
            });
        }
        //按照创建时间倒序、业务模块和分类正序排序
        queryWrapper.lambda().orderByDesc(FormLayout::getCreateTime)
                .orderByAsc(FormLayout::getBusinessModule)
                .orderByAsc(FormLayout::getClassificationId);

        IPage<FormLayout> page = findPageVue(currentPage, pageSize,queryWrapper);
        List<FormLayout> formLayoutList= page.getRecords();

        List<DriverLibrary> driverLibraryList = driverLibraryService.findListByIds(formLayoutList.stream().map(FormLayout::getClassificationId).collect(Collectors.toSet()));

        List<Chip> chipList = chipService.findListByIds(driverLibraryList.stream().map(DriverLibrary::getChipId).collect(Collectors.toSet()));

        List<Map<String,Integer>> formPropertyList = formPropertyService.getBaseMapper().groupList();

        JSONArray dataArray = new JSONArray();
        for (FormLayout formLayout : formLayoutList){
            JSONObject layoutData = new JSONObject();
            layoutData.put("layoutId",formLayout.getLayoutId());
            layoutData.put("layoutName",formLayout.getLayoutName());
            Integer businessModule = formLayout.getBusinessModule();
            layoutData.put("businessModule",businessModule);
            layoutData.put("classificationId",formLayout.getClassificationId());

            FormBusinessModuleEnum businessModuleEnum = EnumUtil.getEnumObject(FormBusinessModuleEnum.class, e->e.getModuleId().equals(businessModule)).orElse(null);
            layoutData.put("businessModuleName",businessModuleEnum.getModuleDescription());

            if (FormBusinessModuleEnum.SLAVE_CHIP_PARAMETER.getModuleId().equals(businessModule)){
                DriverLibrary driverLibrary = driverLibraryList.stream().filter(e ->e.getDriverLibraryId().equals(formLayout.getClassificationId())).findFirst().orElse(null);
                String classificationName = "";
                if (driverLibrary != null){
                    Chip chip = chipList.stream().filter(e ->e.getChipId().equals(driverLibrary.getChipId())).findFirst().orElse(null);
                    if (chip != null){
                        classificationName = chip.getDisplayName() + "驱动-" + driverLibrary.getCompatible();
                    }
                }
                layoutData.put("classificationName",classificationName);
            }

            layoutData.put("components", JSON.parseObject(formLayout.getComponents()));
            layoutData.put("createTime",formLayout.getCreateTime());
            layoutData.put("updateTime",formLayout.getUpdateTime());

            Boolean isUsed = false;
            if (!formPropertyList.isEmpty()){
                List<Map<String,Integer>> matchList = formPropertyList.stream().filter(f ->formLayout.getBusinessModule().equals(f.get("business_module")) && formLayout.getClassificationId().equals(f.get("classification_id"))).collect(Collectors.toList());
                if (!matchList.isEmpty()){
                    isUsed = true;
                }
            }
            layoutData.put("isUsed",isUsed);

            dataArray.add(layoutData);
        }
        resultData.put(APP.DATA, dataArray);
        resultData.put(APP.TOTAL_COUNT, page.getTotal());
        resultData.put(APP.POS, (currentPage - 1) * pageSize);
        resultData.put(APP.CURRENT_PAGE, page.getCurrent());
        return resultData;
    }

    /**
     * 获取单个表单布局
     *  可根据layoutId查询，也可根据businessModule和classificationId组合查询
     * @return
     */
    public JSONObject getOneFormLayout(JSONObject query){
        JSONObject components = new JSONObject();
        Integer layoutId = query.getInteger("layoutId");
        Integer businessModule = query.getInteger("businessModule");
        Integer classificationId = query.getInteger("classificationId");
        FormLayout formLayout = null;
        if (layoutId != null){
            formLayout = findOneByProperties(new String[]{"layoutId"},new Integer[]{layoutId});
        }
        if (businessModule !=null && classificationId !=null){
            formLayout = findOneByProperties(new String[]{"businessModule","classificationId"},new Integer[]{businessModule,classificationId});
        }

        if (formLayout!=null){
            components = JSON.parseObject(formLayout.getComponents());
        }
        return JsonUtil.getSuccess("").fluentPut(APP.DATA, components);
    }

    /**
     * 根据分类IDS查询模块下布局列表
     * @param businessModule
     * @param classificationIds
     * @return
     */
    public List<JSONObject> getListByClassificationIds(Integer businessModule,Set<Integer> classificationIds){
        if (classificationIds.isEmpty()){
            return new ArrayList<>();
        }
        QueryWrapper<FormLayout> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(FormLayout::getBusinessModule,businessModule);
        queryWrapper.lambda().in(FormLayout::getClassificationId,classificationIds);
        List<FormLayout> formLayoutList= list(queryWrapper);
        List<JSONObject> dataList = new ArrayList<>();
        for (FormLayout formLayout : formLayoutList){
            JSONObject layoutData = new JSONObject();
            layoutData.put("classificationId",formLayout.getClassificationId());
            layoutData.put("components", JSON.parseObject(formLayout.getComponents()));
            dataList.add(layoutData);
        }
        return dataList;
    }

    /**
     * 获取多个表单布局
     *  根据businessModule查询
     * @return
     */
    public JSONObject getAllFormLayout(JSONObject query){
        Integer businessModule = query.getInteger("businessModule");
        List<FormLayout> formLayoutList= findByProperty("businessModule",businessModule);
        JSONArray dataArray = new JSONArray();
        for (FormLayout formLayout : formLayoutList){
            JSONObject layoutData = new JSONObject();
            layoutData.put("classificationId",formLayout.getClassificationId());
            layoutData.put("components", JSON.parseObject(formLayout.getComponents()));

            dataArray.add(layoutData);
        }
        return JsonUtil.getSuccess("").fluentPut(APP.DATA, dataArray);
    }

    /**
     * 获取表单类别列表
     * @return
     */
    public JSONObject getClassificationList(Integer businessModule){
        if (businessModule == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }
        JSONArray classificationArray = new JSONArray();
        if (FormBusinessModuleEnum.SLAVE_CHIP_PARAMETER.getModuleId().equals(businessModule)){
            List<DriverLibrary> driverLibraryList = driverLibraryService.findByProperty(DriverLibrary::getType,ChipTypeEnum.SLAVE.getType());
            List<Chip> chipList = chipService.findListByIds(driverLibraryList.stream().map(DriverLibrary::getChipId).collect(Collectors.toSet()));
            for(DriverLibrary driverLibrary : driverLibraryList){
                JSONObject classificationData = new JSONObject();
                Chip chip = chipList.stream().filter(e ->e.getChipId().equals(driverLibrary.getChipId())).findFirst().orElse(null);
                String namePrefix = chip == null ? "" : chip.getDisplayName();
                classificationData.put("id",driverLibrary.getDriverLibraryId());
                classificationData.put("label",namePrefix + "驱动-" + driverLibrary.getCompatible());
                classificationData.put("children",null);
                classificationArray.add(classificationData);
            }
        }
        return JsonUtil.getSuccess("").fluentPut(APP.DATA, classificationArray);
    }

    /**
     * 获取表单组件
     * @param query
     * @return
     */
    public JSONObject getFormComponents(JSONObject query){
        JSONArray resultArray = new JSONArray();
        JSONObject layoutData = getOneFormLayout(query);
        FormLayout formLayout = (FormLayout) layoutData.get(APP.DATA);
        Integer layoutId = formLayout.getLayoutId();
        List<FormComponent> formComponentList = formComponentService.findByProperty("layoutId",layoutId);
        Set<Integer> definitionIds = formComponentList.stream().map(FormComponent::getPropertyDefinitionId).collect(Collectors.toSet());
        List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.findListByIds(definitionIds);
        for (FormComponent component : formComponentList){
            JSONObject componentData = new JSONObject();
            FormPropertyDefinition definition = definitionList.stream().filter(d->d.getPropertyDefinitionId().equals(component.getPropertyDefinitionId())).findFirst().orElse(null);
            componentData.put("propertyKey",definition.getPropertyKey());
            componentData.put("propertyName",definition.getPropertyName());
            resultArray.add(componentData);
        }

        return JsonUtil.getSuccess("").fluentPut(APP.DATA, resultArray);
    }

    /**
     * 增加表单信息(不包括组件布局内容)
     * @return
     */
    public JSONObject addFormLayoutExcludeComponents(JSONObject data, Users currentUser){
        String layoutName = data.getString("layoutName");
        Integer businessModule = data.getInteger("businessModule");
        Integer classificationId = data.getInteger("classificationId");
        if (StringUtil.isNullOrEmpty(layoutName) || businessModule == null || classificationId == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }
        List<FormLayout> formLayoutList = findByProperties(new String[]{"businessModule","layoutName"},new Object[]{businessModule,layoutName});
        if (!formLayoutList.isEmpty()){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "表单名称重复,请重新输入!");
        }
        formLayoutList = findByProperties(new String[]{"businessModule","classificationId"},new Integer[]{businessModule,classificationId});
        if (!formLayoutList.isEmpty()){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "该类别表单已存在，请重新选择!");
        }

        JSONObject components = data.getJSONObject("components");
        FormLayout formLayout = new FormLayout();
        formLayout.setLayoutName(layoutName.trim());
        formLayout.setComponents(JSONObject.toJSONString(components, SerializerFeature.WriteMapNullValue));
        formLayout.setClassificationId(classificationId);
        formLayout.setBusinessModule(businessModule);
        formLayout.setCreatorId(currentUser.getUserId());
        save(formLayout);

        JSONObject resultData = new JSONObject();
        resultData.put("layoutId",formLayout.getLayoutId());
        resultData.put("businessModule",businessModule);
        resultData.put("components",components);

        return JsonUtil.getSuccess("").fluentPut(APP.DATA, resultData);
    }

    /**
     * 编辑表单信息(不包括组件布局内容)
     * @return
     */
    public JSONObject editFormLayoutExcludeComponents(JSONObject data, Users currentUser){
        Integer layoutId = data.getInteger("layoutId");
        String layoutName = data.getString("layoutName");
        Integer businessModule = data.getInteger("businessModule");
        Integer classificationId = data.getInteger("classificationId");
        if (StringUtil.isNullOrEmpty(layoutName) || layoutId == null || businessModule == null || classificationId == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }
        FormLayout formLayout = getById(layoutId);
        if (formLayout == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }

        LambdaQueryWrapper<FormLayout> formLayoutLambdaQueryWrapper = new LambdaQueryWrapper<>();
        formLayoutLambdaQueryWrapper.eq(FormLayout::getBusinessModule,businessModule).eq(FormLayout::getLayoutName,layoutName);
        formLayoutLambdaQueryWrapper.ne(FormLayout::getLayoutId,layoutId);
        List<FormLayout> formLayoutList = list(formLayoutLambdaQueryWrapper);
        if (!formLayoutList.isEmpty()){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "表单名称重复,请重新输入!");
        }

        formLayoutLambdaQueryWrapper = new LambdaQueryWrapper<>();
        formLayoutLambdaQueryWrapper.eq(FormLayout::getBusinessModule,businessModule).eq(FormLayout::getClassificationId,classificationId);
        formLayoutLambdaQueryWrapper.ne(FormLayout::getLayoutId,layoutId);
        formLayoutList = list(formLayoutLambdaQueryWrapper);
        if (!formLayoutList.isEmpty()){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "该类别表单已存在，请重新选择!");
        }

        formLayout.setLayoutName(layoutName.trim());
        formLayout.setClassificationId(classificationId);
        formLayout.setBusinessModule(businessModule);
        formLayout.setUpdateUserId(currentUser.getUserId());
        updateById(formLayout);

        return JsonUtil.getSuccess("");
    }

    /**
     * 删除表单
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject deleteFormLayout(Integer layoutId){
        if (layoutId == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }
        removeById(layoutId);
        List<FormComponent> componentList = formComponentService.findByProperty("layoutId",layoutId);
        if (!componentList.isEmpty()){
            formComponentService.deleteBatchByIds(componentList.stream().map(FormComponent::getComponentId).collect(Collectors.toList()));
        }
        return JsonUtil.getSuccess("");
    }

    /**
     * 编辑表单布局
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject editFormLayout(JSONObject data, Users currentUser){
        Integer businessModule = data.getInteger("businessModule");
        Integer layoutId = data.getInteger("layoutId");
        JSONObject components = data.getJSONObject("components");
        JSONArray optionsArray = data.getJSONArray("options");

        if (businessModule == null || layoutId == null  || optionsArray == null || components == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }
        FormLayout formLayout = getById(layoutId);
        if (formLayout == null){
            return JsonUtil.getFail(ErrorCodeEnum.INVALID_PARAM, "请检查参数!");
        }

        Boolean isRepeatOfComponent = formComponentService.editBatchFormLayout(layoutId,optionsArray);
        //判断组件属性是否重复
        if (isRepeatOfComponent){
            return JsonUtil.getFail(ErrorCodeEnum.DUPLICATE_DATA, "当前表单内组件属性[字段名]重复,请重新设置!");
        }

        formLayout.setComponents(JSONObject.toJSONString(components, SerializerFeature.WriteMapNullValue));
        formLayout.setUpdateUserId(currentUser.getUserId());
        updateById(formLayout);

        return JsonUtil.getSuccess("");
    }


    /**
     * 根据芯片参数生成表单布局
     * @param layoutName
     * @param classificationId
     * @param businessModule
     * @param userId
     * @param chipParameterList
     */
    public Integer generateLayoutByParameters(String layoutName,Integer classificationId,Integer businessModule,Integer userId,List<ChipParameter> chipParameterList){
        List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.findByProperty(FormPropertyDefinition::getBusinessModule,businessModule);
        FormLayout layout = findOneByProperties(new String[]{"businessModule","classificationId"},new Object[]{businessModule,classificationId});
        if (layout == null){
            layout = new FormLayout();
            layout.setCreatorId(userId);
        }else {
            layout.setUpdateUserId(userId);
        }
        layout.setLayoutName(layoutName + "表单");
        layout.setClassificationId(classificationId);
        layout.setBusinessModule(businessModule);
        JSONArray fields = new JSONArray();
        for (ChipParameter chipParameter : chipParameterList){
            String symbol = chipParameter.getSymbol();
            FormPropertyDefinition definition = definitionList.stream().filter(e ->e.getPropertyKey().equals(symbol)).findFirst().orElse(null);
            if (definition != null){
                Integer propertyDefinitionId = definition.getPropertyDefinitionId();
                JSONObject component = new JSONObject();
                String description = chipParameter.getDescription();
                String dataType = chipParameter.getDataType();
                String validValues = chipParameter.getValidValues();
                if (StringUtils.isNotBlank(validValues)){
                    if (validValues.indexOf(",") > -1 || ParameterConfigurationDataTypeEnum.ENUM.getType().equals(dataType)){
                        LinkedHashMap<String, String> optionMap = getOptionListByValues(chipParameter.getValidValues(),chipParameter.getDisplayValues());
                        component = FormBuilder.buildSelectObject(description,symbol,24,optionMap,propertyDefinitionId);
                    }
                    if (validValues.indexOf("~") > -1){
                        Integer min = Integer.parseInt(validValues.split("~")[0]);
                        Integer max = Integer.parseInt(validValues.split("~")[1]);
                        component = FormBuilder.buildInputNumberObject(description,symbol,min,max,24,propertyDefinitionId);
                    }
                }else if(StringUtils.isBlank(validValues) && StringUtils.equalsAny(dataType,ParameterConfigurationDataTypeEnum.INTEGER.getType(),ParameterConfigurationDataTypeEnum.FLOAT.getType())){
                    component = FormBuilder.buildInputNumberObject(description,symbol,null,null,24,propertyDefinitionId);
                }else if (ParameterConfigurationDataTypeEnum.BOOLEAN.getType().equals(dataType)){
                    component = FormBuilder.buildSwitchObject(description,symbol,24,propertyDefinitionId);
                }else {
                    component = FormBuilder.buildInputObject(description,symbol,24,propertyDefinitionId);
                }
                fields.add(component);
            }
        }
        JSONObject components = FormBuilder.addFormComponents(fields);
        layout.setComponents(JSONObject.toJSONString(components, SerializerFeature.WriteMapNullValue));
        saveOrUpdate(layout);

        //覆盖表单组件信息
        formComponentService.overwriteByParameters(layout.getLayoutId(),classificationId,chipParameterList);
        return layout.getLayoutId();
    }

    /**
     * 根据数据范围获取选择框选项
     * @param validValues
     * @param displayValues
     */
    public LinkedHashMap<String, String> getOptionListByValues(String validValues,String displayValues){
        LinkedHashMap<String, String> optionMap = new LinkedHashMap<>();
        String[] validValueArray = validValues.split(",");
        for (int i = 0; i < validValueArray.length; i++) {
            if (StringUtils.isBlank(displayValues)){
                optionMap.put(validValueArray[i],validValueArray[i]);
            }else {
                optionMap.put(displayValues.split(",")[i],validValueArray[i]);
            }
        }
        return optionMap;
    }

}
